#include <mpi.h>
#include <stdio.h>
#include "utils.h"

//! 参考文档: https://blog.csdn.net/andyelvis/article/details/42675971
int main(int argc, char** argv) {
    int rank, size;
    int dims[2]    = {2, 2};      // 定义一个4x4的网格
    int periods[2] = {1, 1};      //! 周期性边界, 类似力学中的周期边界条件，最右边的右邻居是左边第一个(其它同理)
    int coords[2];                //! rank在笛卡尔坐标系内的各个维度上的坐标
    MPI_Comm cart_comm;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    // 创建笛卡尔拓扑
    //! 进程号在二维网格中按行存储
    MPI_Cart_create(MPI_COMM_WORLD,  2, dims, periods, 0, &cart_comm);
    MPI_Cart_coords(cart_comm, rank, 2, coords);

    // 打印每个进程的坐标
    // INFO("rank %d: coord (%d, %d)\n", rank, coords[0], coords[1]);

    //! 获取每个进程的上下左右邻居的rank
    //! no periods
    // [INFO] rank 0: shift (-2, 2, -2, 1)
    // [INFO] rank 2: shift (0, -2, -2, 3)
    // [INFO] rank 3: shift (1, -2, 2, -2)
    // [INFO] rank 1: shift (-2, 3, 0, -2)

    //! with periods
    // [INFO] rank 2: shift (0, 0, 3, 3)
    // [INFO] rank 3: shift (1, 1, 2, 2)
    // [INFO] rank 0: shift (2, 2, 1, 1)
    // [INFO] rank 1: shift (3, 3, 0, 0)
    int rank_up, rank_down, rank_left, rank_right;
    MPI_Cart_shift(cart_comm, 0 /*row*/, 1, &rank_up,   &rank_down);   /*得到当前进程上下两侧的进程标识*/
    MPI_Cart_shift(cart_comm, 1 /*col*/, 1, &rank_left, &rank_right);  /*得到当前进程左右两侧的进程标识*/
    INFO("rank %d: shift (%d, %d, %d, %d)\n", rank, rank_up, rank_down, rank_left, rank_right);

    //! 进行一些简单的通信，例如与右邻居通信
    // 进程向右边邻居发送消息
    // if (rank_right != MPI_PROC_NULL) {
    //     int message = rank;
    //     MPI_Send(&message, 1, MPI_INT, rank_right, 0, cart_comm);
    //     printf("Process %d sent message %d to right neighbor %d\n", rank, message, rank_right);
    // }

    // if (rank_left != MPI_PROC_NULL) {
    //     int received_message;
    //     MPI_Recv(&received_message, 1, MPI_INT, rank_left, 0, cart_comm, MPI_STATUS_IGNORE);
    //     printf("Process %d received message %d from left neighbor %d\n", rank, received_message, rank_left);
    // }

    MPI_Finalize();
    return 0;
}